import sys
import os.path
from _winreg import HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, QueryValueEx, OpenKey
from ConfigParser import RawConfigParser
from .dprparser import UnitInUses
from .utils import warning, canonical
from .cpinfo import getwindowsencoding

class DelphiUnitSearcher:
    project_dcu_dir = ''
    project_dir = ''
    delphi_root_dir = ''

    def __init__(self, project=''):
        self.library_search_path = []
        self.project_search_path = []
        self.include_search_path = []
        self.units = {}
        self.unit_aliases = {}
        self._init_from_registry()
        if project:
            dof = os.path.splitext(project)[0] + '.dof'
            self._init_from_dof(dof)

    def _init_from_registry(self):
        try:
            with OpenKey(HKEY_LOCAL_MACHINE, ur'Software\Borland\Delphi\4.0') as key:
                self.delphi_root_dir, valuetype = QueryValueEx(key, u'RootDir')
        except WindowsError:
            warning(u"Cannot read Delphi configuration from registry")
            return

        with OpenKey(HKEY_CURRENT_USER, ur'Software\Borland\Delphi\4.0\Library') as key:
            library_search_path, valuetype = QueryValueEx(key, u'Search Path')
            library_search_path = library_search_path.replace(u'$(DELPHI)', self.delphi_root_dir)
            self.library_search_path = library_search_path.split(u';')
            unit_aliases, valuetype = QueryValueEx(key, u'Unit Aliases')
            self.unit_aliases = dict(pair.split(u'=') for pair in unit_aliases.split(u';') if u'=' in pair)

    def _init_from_dof(self, dof):
        # [Compiler]
        # UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
        # [Directories]
        # UnitOutputDir=.\dcu
        # SearchPath=c:\prog\algo;d:\otro\directorio;
        dofdir = os.path.dirname(dof)
        self.project_dir = dofdir
        config = RawConfigParser()
        config.read(dof)
        if config.has_option('Compiler', 'UnitAliases'):
            unit_aliases = config.get('Compiler', 'UnitAliases')
            self.unit_aliases.update(dict(pair.split('=') for pair in unit_aliases.split(';') if '=' in pair))
        if config.has_option('Directories', 'UnitOutputDir'):
            output = config.get('Directories', 'UnitOutputDir')
            self.project_dcu_dir = canonical(output, self.project_dir)
        if config.has_option('Directories', 'SearchPath'):
            project_search_path = config.get('Directories', 'SearchPath')
            project_search_path = project_search_path.replace('$(DELPHI)', self.delphi_root_dir)
            self.project_search_path = [
                canonical(dir, self.project_dir) for dir in project_search_path.split(';')]

    @property
    def effective_search_path(self):
        return [self.project_dir] + self.project_search_path + self.library_search_path

    def is_known(self, uname):
        return uname.lower() in self.units

    def locate_unit(self, uname):
        join = os.path.join
        isfile = os.path.isfile
        dir, uname = os.path.split(uname)
        uname, ext = os.path.splitext(uname)
        uname = self.unit_aliases.get(uname, uname) # filter aliases
        key = uname.lower()

        if dir:
            dirs_to_test = [canonical(dir, self.project_dir)]
            if key in self.units:
                warning(u"Duplicate unit '%s': '%s' and '%s'" % (key, self.units[key].path, dirs_to_test[0]))
        else:
            dirs_to_test = self.effective_search_path

        unit = self.units.get(key)
        if unit:
            return unit

        if ext:
            exts_to_test = [ext]
        else:
            exts_to_test = ['.pas', '.dcu']

        found = False
        for dir in dirs_to_test:
            for ext in exts_to_test:
                fullpath = join(dir, uname) + ext
                if isfile(fullpath):
                    found = True
                    break
            if found:
                break
        if not found:
            fullpath = ''
            warning(u"Could not find unit: '%s'" % uname)

        unit = UnitInUses(uname, fullpath)
        if fullpath:
            dfm = os.path.splitext(fullpath)[0] + '.dfm'
            if isfile(dfm):
                try: 
                    with open(dfm) as f:
                        line = f.readline()
                        if line[:6]=='object':
                            unit.form = u'{' + line.split(':',1)[1].strip() + u'}'
                except Exception: # ignore errors
                    pass
        self.units[key] = unit
        
        return unit
